package com.mastercard.labs

class DealService {
	def cardService
	Calendar cal = Calendar.getInstance()

	/**
	 * Return ArrayList of merchants, with
	 * associated score, rank descending
	 * @param user
	 * @return
	 */
	def getFavoriteMerchants(User user) {
		// Favorite merchants are the merchant with number of transaction
		// higher than average per year
		def cards = cardService.getCards(user)
		cal.setTime(new Date())
		cal.roll(Calendar.YEAR, false)
		def lastYear = cal.getTime()
		def qry = Transaction.where {
			(txnDate > lastYear) && (card in cards)
		}
		def lastYearTxns =  qry.findAll()

		def merchants = new ArrayList()
		for (txn in lastYearTxns) {
			merchants.add(txn.merchant)
		}

		// Calculate number of transaction for each merchant
//		def duplicateMap = new HashMap()
//		for (txn in lastYearTxns) {
//			def merchant = txn.merchant
//
//			if (duplicateMap.containsKey(merchant)) {
//				def duplicate = duplicateMap.get(merchant)
//				duplicateMap.put(merchant, duplicate + 1)
//			} else {
//				duplicateMap.put(merchant, 1)
//			}
//		}
//		println duplicateMap
//
//		// Finding number of average transaction per merchant
//		Set<String> visitsSet = new LinkedHashSet<String>(duplicateMap.values());
//		int sum = 0, avg=0
//		for (i in visitsSet) {
//			sum += i
//		}
//		if (visitsSet.size() > 0) {
//			avg = sum/visitsSet.size()
//		}
//
//		// Filter the merchant with number of transaction higher than average
//		for (key in duplicateMap.keySet()) {
//			if (duplicateMap.get(key) > avg) {
//				merchants.add(key)
//			}
//		}
		return merchants
	}


	/**
	 * Return average of spending for each category
	 * Should return a map
	 * @param user
	 * @return
	 */
	def getAverageSpending(User user) {
		def cards = cardService.getCards(user)
		cal.setTime(new Date())
		cal.roll(Calendar.YEAR, false)
		def lastYear = cal.getTime()
		def qry = Transaction.where {
			(txnDate > lastYear) && (card in cards)
		}
		def lastYearTxns =  qry.findAll()

		if (lastYearTxns.size() == 0) {
			return 0
		}

		def sum = 0
		for (txn in lastYearTxns) {
			sum  =  sum + txn.amount
		}
		def avg = 0

		return sum/lastYearTxns.size()
	}

	/**
	 * Return favorite categories with score,
	 * rank descending
	 * @param userId
	 * @return
	 */
	def getFavoriteCategory(User user) {

	}

	/**
	 * Return favorite locations that user likes
	 * to do shoping with associated score
	 * @param userId
	 * @return
	 */
	def getFavoriteLocation(User user) {

	}


	/**
	 * Return user gender to calculate deal similarity
	 * @param user
	 * @return
	 */
	def getUserGender(User user) {
		return user.gender
	}

	/**
	 * Return user age to calculate deal similarity
	 * @param user
	 * @return
	 */
	def getUserAge(User user) {
		if (user.birthDate == null) {
			return 0
		}
		cal.setTime(new Date())
		def currentYear = cal.get(Calendar.YEAR)

		cal.setTime(user.birthDate)
		def dob = cal.get(Calendar.YEAR)
		return (currentYear - dob)
	}


	/**
	 * Algorithm to calculate the score of deal
	 * based on user spending preference
	 * @param deal
	 * @return
	 */
	def getScore(Deal deal) {

	}


	/**
	 * Return list of deals, ranked by score descending.
	 * The score will be calculated with the user spending
	 * preference
	 * @param user
	 * @return
	 */
	def getDeals(User user) {
		if(!user){
			return Deal.findAll()
		}
		def favMerchants = getFavoriteMerchants(user)
		def avgSpending = getAverageSpending(user)

		// If we don't have much data about user, just return random Deal
		if (avgSpending == 0 || favMerchants.size() == 0) {
			return Deal.findAll()
		} 
		else {
			def qry = Deal.where {
				(merchant in favMerchants) && (price < avgSpending)
			}
			return qry.findAll()
		}
	}
	
	def searchDeals(searchTitle) {		
		def merchants = Merchant.createCriteria().list {
			ilike("name", "%" + searchTitle + "%")
		}
		
		def results = Deal.createCriteria().list {				
			or {
				ilike("title", "%" + searchTitle + "%")
				ilike("description", "%" + searchTitle + "%")
				inList("merchant", merchants)
				ilike("tags", "%" + searchTitle + "%")
			}
		}
		return results
	}
	
	def searchDealsInCategorires(categories) {
		ArrayList categoriesLong = new ArrayList()
		for (String c in categories) {
			long num = Long.parseLong(c)
			categoriesLong.add(num)
		}

		def results = Deal.executeQuery(
			'select distinct a from Deal a join a.categories category where category.id in (:categories)',
			[categories: categoriesLong])

		return results
	}
	
	def searchByCondition(searchTitle, searchCountry, searchMerchant, searchCategory){
		def result = Deal.createCriteria().list {
			if(searchTitle)
				ilike("title", "%" + searchTitle + "%")	
			if(searchCountry) {
					country {
					eq("id", searchCountry as Long)
				}
			}
			if(searchMerchant) {
					merchant {
					eq("id", searchMerchant as Long)
				}
			}
			if(searchCategory) {
					categories {
						eq("id", searchCategory as Long)
				}
			}
		}
		
	}
	
	def searchDealForDashboard(){
		def result = Deal.createCriteria().list {
			order("startDate", "desc")
			maxResults(5)
		}
		return result
	}
}
